import * as THREE from 'three';
import { CONFIG } from '@/core/constants';
import { ChunkPosition } from '@/core/types';
import { BlockType } from '@/blocks/types';

export class Chunk {
  public position: ChunkPosition;
  private blocks: Uint8Array;
  private mesh: THREE.Group | null = null;
  private needsUpdate = true;

  constructor(position: ChunkPosition) {
    this.position = position;
    this.blocks = new Uint8Array(CONFIG.CHUNK_SIZE * CONFIG.WORLD_HEIGHT * CONFIG.CHUNK_SIZE);
    this.generateTerrain();
  }

  private generateTerrain(): void {
    // 首先生成基础地形
    for (let x = 0; x < CONFIG.CHUNK_SIZE; x++) {
      for (let z = 0; z < CONFIG.CHUNK_SIZE; z++) {
        const worldX = this.position.x * CONFIG.CHUNK_SIZE + x;
        const worldZ = this.position.z * CONFIG.CHUNK_SIZE + z;
        
        const height = this.getTerrainHeight(worldX, worldZ);
        
        for (let y = 0; y < height && y < CONFIG.WORLD_HEIGHT; y++) {
          let blockType: BlockType;
          
          if (y === height - 1 && y > 30) {
            blockType = BlockType.GRASS;
          } else if (y > height - 4 && y > 30) {
            blockType = BlockType.DIRT;
          } else if (y < 5) {
            blockType = Math.random() < 0.1 ? BlockType.COAL_ORE : BlockType.STONE;
          } else {
            blockType = BlockType.STONE;
          }
          
          this.setBlock(x, y, z, blockType);
        }
      }
    }
    
    // 然后生成树木
    this.generateTrees();
  }

  private generateTrees(): void {
    const treeChance = 0.15; // 增加到15%的概率生成树木，让世界更丰富
    let treesGenerated = 0;
    
    for (let x = 2; x < CONFIG.CHUNK_SIZE - 2; x++) {
      for (let z = 2; z < CONFIG.CHUNK_SIZE - 2; z++) {
        if (Math.random() < treeChance) {
          // 找到地面高度
          let groundY = -1;
          for (let y = CONFIG.WORLD_HEIGHT - 1; y >= 0; y--) {
            const blockType = this.getBlock(x, y, z);
            if (blockType === BlockType.GRASS) {
              groundY = y + 1;
              break;
            }
          }
          
          if (groundY > 0 && groundY < CONFIG.WORLD_HEIGHT - 8) {
            // 检查是否有足够空间生成树
            if (this.canPlaceTree(x, groundY, z)) {
              this.generateTree(x, groundY, z);
              treesGenerated++;
            }
          }
        }
      }
    }
    
    console.log(`Chunk (${this.position.x}, ${this.position.z}) generated ${treesGenerated} trees`);
  }

  private canPlaceTree(x: number, y: number, z: number): boolean {
    // 检查树干位置是否为空气
    for (let i = 0; i < 6; i++) {
      if (this.getBlock(x, y + i, z) !== BlockType.AIR) {
        return false;
      }
    }
    
    // 检查周围是否有足够空间
    for (let dx = -2; dx <= 2; dx++) {
      for (let dz = -2; dz <= 2; dz++) {
        for (let dy = 4; dy < 7; dy++) {
          const checkX = x + dx;
          const checkZ = z + dz;
          const checkY = y + dy;
          
          if (checkX >= 0 && checkX < CONFIG.CHUNK_SIZE && 
              checkZ >= 0 && checkZ < CONFIG.CHUNK_SIZE &&
              checkY < CONFIG.WORLD_HEIGHT) {
            if (this.getBlock(checkX, checkY, checkZ) !== BlockType.AIR) {
              return false;
            }
          }
        }
      }
    }
    
    return true;
  }

  private generateTree(x: number, y: number, z: number): void {
    // 随机选择树的类型
    const treeTypes = ['oak', 'birch', 'spruce'];
    const treeType = treeTypes[Math.floor(Math.random() * treeTypes.length)];
    
    switch (treeType) {
      case 'oak':
        this.generateOakTree(x, y, z);
        break;
      case 'birch':
        this.generateBirchTree(x, y, z);
        break;
      case 'spruce':
        this.generateSpruceTree(x, y, z);
        break;
    }
  }

  private generateOakTree(x: number, y: number, z: number): void {
    const trunkHeight = 4 + Math.floor(Math.random() * 2); // 4-5格高
    
    // 生成树干
    for (let i = 0; i < trunkHeight; i++) {
      this.setBlock(x, y + i, z, BlockType.LOG);
    }
    
    // 生成树叶层
    const leafY = y + trunkHeight - 1;
    
    // 顶层树叶 (3x3)
    for (let dx = -1; dx <= 1; dx++) {
      for (let dz = -1; dz <= 1; dz++) {
        if (Math.random() > 0.1 && this.isValidPosition(x + dx, leafY + 1, z + dz)) {
          this.setBlock(x + dx, leafY + 1, z + dz, BlockType.LEAVES);
        }
      }
    }
    
    // 中层树叶 (5x5)
    for (let dx = -2; dx <= 2; dx++) {
      for (let dz = -2; dz <= 2; dz++) {
        const distance = Math.abs(dx) + Math.abs(dz);
        if (distance <= 2 && Math.random() > 0.05 && this.isValidPosition(x + dx, leafY, z + dz)) {
          this.setBlock(x + dx, leafY, z + dz, BlockType.LEAVES);
        }
      }
    }
    
    // 底层树叶 (5x5，稍微稀疏)
    for (let dx = -2; dx <= 2; dx++) {
      for (let dz = -2; dz <= 2; dz++) {
        const distance = Math.abs(dx) + Math.abs(dz);
        if (distance <= 2 && Math.random() > 0.2 && this.isValidPosition(x + dx, leafY - 1, z + dz)) {
          this.setBlock(x + dx, leafY - 1, z + dz, BlockType.LEAVES);
        }
      }
    }
  }

  private generateBirchTree(x: number, y: number, z: number): void {
    const trunkHeight = 5 + Math.floor(Math.random() * 1); // 5-5格高
    
    // 生成树干
    for (let i = 0; i < trunkHeight; i++) {
      this.setBlock(x, y + i, z, BlockType.BIRCH_LOG);
    }
    
    // 生成树叶（白桦树的树叶更加紧凑）
    const leafY = y + trunkHeight - 1;
    
    // 顶层
    if (this.isValidPosition(x, leafY + 1, z)) {
      this.setBlock(x, leafY + 1, z, BlockType.BIRCH_LEAVES);
    }
    
    // 中层 (3x3)
    for (let dx = -1; dx <= 1; dx++) {
      for (let dz = -1; dz <= 1; dz++) {
        if (Math.random() > 0.1 && this.isValidPosition(x + dx, leafY, z + dz)) {
          this.setBlock(x + dx, leafY, z + dz, BlockType.BIRCH_LEAVES);
        }
      }
    }
    
    // 底层 (3x3)
    for (let dx = -1; dx <= 1; dx++) {
      for (let dz = -1; dz <= 1; dz++) {
        if (Math.random() > 0.2 && this.isValidPosition(x + dx, leafY - 1, z + dz)) {
          this.setBlock(x + dx, leafY - 1, z + dz, BlockType.BIRCH_LEAVES);
        }
      }
    }
  }

  private generateSpruceTree(x: number, y: number, z: number): void {
    const trunkHeight = 6 + Math.floor(Math.random() * 2); // 6-7格高
    
    // 生成树干
    for (let i = 0; i < trunkHeight; i++) {
      this.setBlock(x, y + i, z, BlockType.SPRUCE_LOG);
    }
    
    // 生成锥形树叶
    const leafY = y + trunkHeight - 1;
    
    // 顶部尖端
    if (this.isValidPosition(x, leafY + 2, z)) {
      this.setBlock(x, leafY + 2, z, BlockType.SPRUCE_LEAVES);
    }
    
    // 从上到下生成锥形树叶
    for (let layer = 0; layer < 4; layer++) {
      const currentY = leafY + 1 - layer;
      const radius = Math.min(layer + 1, 2);
      
      for (let dx = -radius; dx <= radius; dx++) {
        for (let dz = -radius; dz <= radius; dz++) {
          const distance = Math.abs(dx) + Math.abs(dz);
          if (distance <= radius && Math.random() > 0.1 && this.isValidPosition(x + dx, currentY, z + dz)) {
            this.setBlock(x + dx, currentY, z + dz, BlockType.SPRUCE_LEAVES);
          }
        }
      }
    }
  }

  private isValidPosition(x: number, y: number, z: number): boolean {
    return x >= 0 && x < CONFIG.CHUNK_SIZE && 
           y >= 0 && y < CONFIG.WORLD_HEIGHT && 
           z >= 0 && z < CONFIG.CHUNK_SIZE;
  }

  private getTerrainHeight(x: number, z: number): number {
    const noise1 = Math.sin(x * 0.05) * Math.cos(z * 0.05) * 3;
    const noise2 = Math.sin(x * 0.02) * Math.cos(z * 0.02) * 6;
    return Math.floor(32 + noise1 + noise2); // 基础高度32，适应64高度的世界
  }

  private getBlockIndex(x: number, y: number, z: number): number {
    return x + z * CONFIG.CHUNK_SIZE + y * CONFIG.CHUNK_SIZE * CONFIG.CHUNK_SIZE;
  }

  public setBlock(x: number, y: number, z: number, blockType: BlockType): void {
    if (x < 0 || x >= CONFIG.CHUNK_SIZE || 
        y < 0 || y >= CONFIG.WORLD_HEIGHT || 
        z < 0 || z >= CONFIG.CHUNK_SIZE) {
      return;
    }
    
    const index = this.getBlockIndex(x, y, z);
    this.blocks[index] = blockType;
    this.needsUpdate = true;
  }

  public getBlock(x: number, y: number, z: number): BlockType {
    if (x < 0 || x >= CONFIG.CHUNK_SIZE || 
        y < 0 || y >= CONFIG.WORLD_HEIGHT || 
        z < 0 || z >= CONFIG.CHUNK_SIZE) {
      return BlockType.AIR;
    }
    
    const index = this.getBlockIndex(x, y, z);
    return this.blocks[index];
  }

  public getMesh(): THREE.Group | null {
    return this.mesh;
  }

  public needsMeshUpdate(): boolean {
    return this.needsUpdate;
  }

  public setMesh(mesh: THREE.Group): void {
    this.mesh = mesh;
    this.needsUpdate = false;
  }

  public dispose(): void {
    if (this.mesh) {
      this.mesh.clear();
    }
  }
}